"""
author: liuxu
date: 2024.12.3
description: 日志打印模块
"""
from loguru import logger
from functools import wraps
from typing import Optional, Dict, Any
import sys
import os
import time
from setting import LOG_DIR, TEST_TYPE


class MyLogger:
    """自动化测试日志公共类"""
    _instance = None  # 单例实例引用
    _initialized = False  # 初始化标记

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(
            self,
            log_dir: str = LOG_DIR,
            log_level: str = "DEBUG",
            retention: str = "10 days",
            rotation: str = "100 MB",
            enqueue: bool = True,
            diagnose: bool = True
    ):
        """
        初始化日志配置
        :param log_dir: 日志存储目录
        :param log_level: 日志级别 DEBUG/INFO/WARNING/ERROR
        :param retention: 日志保留策略
        :param rotation: 日志轮转策略
        :param enqueue: 启用线程安全
        :param diagnose: 记录异常诊断信息
        """
        if self._initialized:  # 防止重复初始化
            return
        self.log_dir = log_dir
        self.log_level = log_level
        self._configure_logger(retention, rotation, enqueue, diagnose)
        self.logger = self.get_logger()

    def _configure_logger(
            self,
            retention: str,
            rotation: str,
            enqueue: bool,
            diagnose: bool
    )-> None:
        """初始化loguru配置（只执行一次）"""
        # 移除默认配置
        logger.remove()

        # 控制台输出格式
        console_format = (
            "<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
            "<level>{level: <8}</level> | "
            "<cyan>{module}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | "
            "<level>{message}</level>"
        )

        # 文件输出格式（增加进程/线程信息）
        file_format = (
            "{time:YYYY-MM-DD HH:mm:ss.SSS} | "
            "{level: <8} | "
            "PID:{process} | TID:{thread} | "
            "{module}:{function}:{line} | "
            "{message}"
        )

        # 控制台输出
        logger.add(
            sys.stderr,
            format=console_format,
            level=self.log_level,
            enqueue=enqueue,
            diagnose=diagnose
        )

        # 文件输出
        if not os.path.exists(self.log_dir):
            os.makedirs(self.log_dir)

        log_file = os.path.join(self.log_dir, f"autotest_{time.strftime('%Y%m%d')}.log")

        logger.add(
            log_file,
            format=file_format,
            level=self.log_level,
            rotation=rotation,
            retention=retention,
            enqueue=enqueue,
            encoding="utf-8",
            diagnose=diagnose
        )

    def bind_context(self, **kwargs: Dict[str, Any]) -> None:
        """绑定上下文信息到日志（如测试用例ID）"""
        logger.configure(extra=kwargs)

    @staticmethod
    def catch_exception(func):
        """异常捕获装饰器（自动记录异常堆栈）"""

        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                logger.opt(exception=True).error(
                    f"Exception occurred: {str(e)}"
                )
                raise

        return wrapper

    @classmethod
    def get_logger(cls) -> logger:
        """获取loguru原生logger对象"""
        return logger

mylogger = MyLogger().get_logger()


# 使用示例
if __name__ == "__main__":
    # 初始化日志
    test_logger = MyLogger(log_level="INFO")

    # 绑定测试上下文
    test_logger.bind_context(
        testcase_id="TC001",
        test_env="staging"
    )

    # 获取原生logger对象
    log = test_logger.get_logger()

    # 记录不同级别日志
    log.debug("Debug message (will not show in INFO level)")
    log.info("Starting test case execution")
    log.warning("Potential compatibility issue detected")


    # 异常捕获示例
    @test_logger.catch_exception
    def test_zero_division_error(a, b):
        return a / b
    try:
        test_zero_division_error(1, 0)
    except Exception:
        pass

